package com.zhiyizhen.handheld.common.view;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;

import com.zhiyizhen.handheld.R;
import com.zhiyizhen.handheld.common.ScreenUtil;
import com.zhiyizhen.handheld.databinding.DialogCommonBinding;


/**
 * 通用对话框，使用同AlertDialog
 */
public class CommonDialog extends Dialog implements View.OnClickListener {

    protected ImageView mIconView;
    protected TextView mTitleView;
    protected TextView mMessageView;

    protected Button mButtonPositive;
    protected Button mButtonNegative;

    private CharSequence mButtonPositiveText;
    private OnClickListener mPositiveButtonListener;

    private CharSequence mButtonNegativeText;
    private OnClickListener mNegativeButtonListener;

    private int mIconId = 0;
    private Drawable mIcon;
    private CharSequence mTitle;
    private CharSequence mMessage;
    private View mView;
    private int mViewLayoutResId;
    private int mMessageGravity = Gravity.CENTER_HORIZONTAL;

    private boolean autoDismiss = true;
    private DialogCommonBinding viewBinding;

    public CommonDialog(@NonNull Context context) {
        this(context, R.style.CommonDialog);
    }

    public CommonDialog(@NonNull Context context, int themeResId) {
        super(context, themeResId);
    }

    protected CommonDialog(@NonNull Context context, boolean cancelable, @Nullable OnCancelListener cancelListener) {
        this(context, R.style.CommonDialog);
        setCancelable(cancelable);
        setOnCancelListener(cancelListener);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().requestFeature(Window.FEATURE_NO_TITLE);

        viewBinding = DialogCommonBinding.inflate(getLayoutInflater());

        setContentView(viewBinding.getRoot());

        setupView();
    }

    @Override
    public void onClick(View view) {
        if (autoDismiss) {
            dismiss();
        }
        if (view == mButtonPositive) {
            if (mPositiveButtonListener != null) {
                mPositiveButtonListener.onClick(this, DialogInterface.BUTTON_POSITIVE);
            }
            return;
        }
        if (view == mButtonNegative && mNegativeButtonListener != null) {
            mNegativeButtonListener.onClick(this, DialogInterface.BUTTON_NEGATIVE);
        }

    }

    public void setIcon(int resId) {
        mIcon = null;
        mIconId = resId;
        if (mIconView != null) {
            if (resId != 0) {
                mIconView.setImageResource(mIconId);
            } else {
                mIconView.setVisibility(View.GONE);
            }
        }
    }

    public void setIcon(Drawable icon) {
        mIcon = icon;
        mIconId = 0;
        if (mIconView != null) {
            if (icon != null) {
                mIconView.setImageDrawable(icon);
            } else {
                mIconView.setVisibility(View.GONE);
            }
        }
    }

    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        if (mTitleView != null) {
            mTitleView.setText(title);
            setupContentMargin();
        }
    }

    public void setMessage(CharSequence message) {
        mMessage = message;
        if (mMessageView != null) {
            mMessageView.setText(message);
            setupContentMargin();
        }
    }

    public void setMessageGravity(int gravity) {
        mMessageGravity = gravity;
        if (mMessageView != null) {
            mMessageView.setGravity(gravity);
        }
    }

    /**
     * Set the view resource to display in the dialog.
     */
    public void setView(int layoutResId) {
        mView = null;
        mViewLayoutResId = layoutResId;
    }

    /**
     * Set the view to display in the dialog.
     */
    public void setView(View view) {
        mView = view;
        mViewLayoutResId = 0;
    }

    /**
     * Set whether the dialog auto dismiss when click the button
     */
    public void setAutoDismiss(boolean autoDismiss) {
        this.autoDismiss = autoDismiss;
    }

    public void setButton(int whichButton, CharSequence text, OnClickListener listener) {
        switch (whichButton) {
            case DialogInterface.BUTTON_POSITIVE:
                mButtonPositiveText = text;
                mPositiveButtonListener = listener;
                break;
            case DialogInterface.BUTTON_NEGATIVE:
                mButtonNegativeText = text;
                mNegativeButtonListener = listener;
                break;
            default:
                throw new IllegalArgumentException("Button does not exist");
        }
    }

    public Button getButton(int whichButton) {
        switch (whichButton) {
            case DialogInterface.BUTTON_POSITIVE:
                return mButtonPositive;
            case DialogInterface.BUTTON_NEGATIVE:
                return mButtonNegative;
            default:
                return null;
        }
    }

    private void setupView() {
        initView();
        setupPanel();

        final boolean hasButtons = setupButtons();
        final View buttonPanel = findViewById(R.id.buttonPanel);
        if (!hasButtons) {
            buttonPanel.setVisibility(View.GONE);
        }

        final LinearLayout contentPanel = findViewById(R.id.contentPanel);
        final FrameLayout customPanel = findViewById(R.id.customPanel);
        final View customView;
        if (mView != null) {
            customView = mView;
        } else if (mViewLayoutResId != 0) {
            final LayoutInflater inflater = LayoutInflater.from(getContext());
            customView = inflater.inflate(mViewLayoutResId, customPanel, false);
        } else {
            customView = null;
        }

        final boolean hasCustomView = customView != null;
        if (!hasCustomView || !canTextInput(customView)) {
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        }

        if (hasCustomView) {
            contentPanel.setVisibility(View.GONE);
            final FrameLayout custom = findViewById(R.id.custom);
            custom.addView(customView, new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        } else {
            customPanel.setVisibility(View.GONE);
            setupContent();
        }
    }

    private void initView() {
        mIconView = viewBinding.ivIcon;
        mTitleView = viewBinding.tvTitle;
        mMessageView = viewBinding.message;
        mButtonPositive = viewBinding.btnRight;
        mButtonNegative = viewBinding.btnLeft;

        mButtonPositive.setOnClickListener(this);
        mButtonNegative.setOnClickListener(this);
    }

    private void setupPanel() {
        final LinearLayout parentPanel = findViewById(R.id.parentPanel);
        final Point point = new Point();
        getWindow().getWindowManager().getDefaultDisplay().getSize(point);

        ViewGroup.LayoutParams params = parentPanel.getLayoutParams();
        params.width = (int) (point.x * 0.4);
        parentPanel.setLayoutParams(params);
    }

    private void setupContent() {
        if (mIconId != 0) {
            mIconView.setImageResource(mIconId);
        } else if (mIcon != null) {
            mIconView.setImageDrawable(mIcon);
        } else {
            mIconView.setVisibility(View.GONE);
        }

        if (!TextUtils.isEmpty(mTitle)) {
            mTitleView.setText(mTitle);
        } else {
            mTitleView.setVisibility(View.GONE);
        }

        if (!TextUtils.isEmpty(mMessage)) {
            mMessageView.setText(mMessage);
            if (mMessageGravity != Gravity.NO_GRAVITY) {
                mMessageView.setGravity(mMessageGravity);
            }
        } else {
            mMessageView.setVisibility(View.GONE);
        }

        setupContentMargin();
    }

    private void setupContentMargin() {
        final boolean hasTitle = !TextUtils.isEmpty(mTitle);
        final boolean hasMessage = !TextUtils.isEmpty(mMessage);

        LinearLayout.LayoutParams params;
        if (hasMessage) {
            params = (LinearLayout.LayoutParams) mMessageView.getLayoutParams();
            params.topMargin = hasTitle ? ScreenUtil.dp2px(12) : 0;
            mMessageView.setLayoutParams(params);
            if (mMessageGravity == Gravity.NO_GRAVITY) {
                mMessageView.setGravity(mMessage.length() > 14 ? Gravity.START : Gravity.CENTER_HORIZONTAL);
            }
        }
    }

    private boolean setupButtons() {
        int bitButtonPositive = 1;
        int bitButtonNegative = 2;

        int whichButtons = 0;

        if (TextUtils.isEmpty(mButtonPositiveText)) {
            mButtonPositive.setVisibility(View.GONE);
        } else {
            mButtonPositive.setText(mButtonPositiveText);
            mButtonPositive.setVisibility(View.VISIBLE);
            whichButtons = whichButtons | bitButtonPositive;
        }

        if (TextUtils.isEmpty(mButtonNegativeText)) {
            mButtonNegative.setVisibility(View.GONE);
        } else {
            mButtonNegative.setText(mButtonNegativeText);
            mButtonNegative.setVisibility(View.VISIBLE);

            whichButtons = whichButtons | bitButtonNegative;
        }

        return whichButtons != 0;
    }

    private static boolean canTextInput(View v) {
        if (v.onCheckIsTextEditor()) {
            return true;
        }

        if (!(v instanceof ViewGroup)) {
            return false;
        }

        ViewGroup vg = (ViewGroup) v;
        int i = vg.getChildCount();
        while (i > 0) {
            i--;
            v = vg.getChildAt(i);
            if (canTextInput(v)) {
                return true;
            }
        }

        return false;
    }

    private static class Params {

        private final Context mContext;

        private int mIconId = 0;
        private Drawable mIcon;
        private CharSequence mTitle;
        private CharSequence mMessage;
        private int mMessageGravity = -1;

        private CharSequence mPositiveButtonText;
        private OnClickListener mPositiveButtonListener;

        private CharSequence mNegativeButtonText;
        private OnClickListener mNegativeButtonListener;

        private boolean mCancelable;
        private OnCancelListener mOnCancelListener;

        private OnDismissListener mOnDismissListener;
        private OnKeyListener mOnKeyListener;

        private View mView = null;
        private int mViewLayoutResId;

        private boolean autoDismiss = true;

        private Params(Context context) {
            mContext = context;
            mCancelable = true;
        }

        private void apply(CommonDialog dialog) {
            dialog.setAutoDismiss(autoDismiss);
            if (mIcon != null) {
                dialog.setIcon(mIcon);
            }
            if (mIconId >= 0) {
                dialog.setIcon(mIconId);
            }
            if (mTitle != null) {
                dialog.setTitle(mTitle);
            }
            if (mMessage != null) {
                dialog.setMessage(mMessage);
            }
            if (mMessageGravity > 0) {
                dialog.setMessageGravity(mMessageGravity);
            }
            if (mPositiveButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
                        mPositiveButtonListener);
            }
            if (mNegativeButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
                        mNegativeButtonListener);
            }
            if (mView != null) {
                dialog.setView(mView);
            } else if (mViewLayoutResId != 0) {
                dialog.setView(mViewLayoutResId);
            }
        }

    }

    public static class Builder {

        private final Params params;

        public Builder(Context context) {
            params = new Params(context);
        }

        public Context getContext() {
            return params.mContext;
        }

        public Builder setAutoDismiss(boolean autoDismiss) {
            params.autoDismiss = autoDismiss;
            return this;
        }

        public Builder setTitle(@StringRes int titleId) {
            return setTitle(params.mContext.getString(titleId));
        }

        public Builder setTitle(CharSequence title) {
            params.mTitle = title;
            return this;
        }

        public Builder setMessage(@StringRes int messageId) {
            params.mMessage = params.mContext.getText(messageId);
            return this;
        }

        public Builder setMessage(CharSequence message) {
            params.mMessage = message;
            return this;
        }

        public Builder setMessageGravity(int gravity) {
            params.mMessageGravity = gravity;
            return this;
        }

        public Builder setIcon(@DrawableRes int iconId) {
            params.mIconId = iconId;
            return this;
        }

        public Builder setIcon(Drawable icon) {
            params.mIcon = icon;
            return this;
        }

        public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) {
            params.mPositiveButtonText = params.mContext.getText(textId);
            params.mPositiveButtonListener = listener;
            return this;
        }

        public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
            params.mPositiveButtonText = text;
            params.mPositiveButtonListener = listener;
            return this;
        }

        public Builder setNegativeButton(@StringRes int textId, final OnClickListener listener) {
            params.mNegativeButtonText = params.mContext.getText(textId);
            params.mNegativeButtonListener = listener;
            return this;
        }

        public Builder setNegativeButton(CharSequence text, final OnClickListener listener) {
            params.mNegativeButtonText = text;
            params.mNegativeButtonListener = listener;
            return this;
        }

        public Builder setCancelable(boolean cancelable) {
            params.mCancelable = cancelable;
            return this;
        }

        public Builder setOnCancelListener(OnCancelListener onCancelListener) {
            params.mOnCancelListener = onCancelListener;
            return this;
        }

        public Builder setOnDismissListener(OnDismissListener onDismissListener) {
            params.mOnDismissListener = onDismissListener;
            return this;
        }

        public Builder setOnKeyListener(OnKeyListener onKeyListener) {
            params.mOnKeyListener = onKeyListener;
            return this;
        }

        public Builder setView(int layoutResId) {
            params.mView = null;
            params.mViewLayoutResId = layoutResId;
            return this;
        }

        public Builder setView(View view) {
            params.mView = view;
            params.mViewLayoutResId = 0;
            return this;
        }

        public CommonDialog create() {
            // Context has already been wrapped with the appropriate theme.
            final CommonDialog dialog = new CommonDialog(params.mContext);
            params.apply(dialog);
            dialog.setCancelable(params.mCancelable);
            if (params.mCancelable) {
                dialog.setCanceledOnTouchOutside(true);
            }
            dialog.setOnCancelListener(params.mOnCancelListener);
            dialog.setOnDismissListener(params.mOnDismissListener);
            if (params.mOnKeyListener != null) {
                dialog.setOnKeyListener(params.mOnKeyListener);
            }
            return dialog;
        }

        public CommonDialog show() {
            final CommonDialog dialog = create();
            dialog.show();
            return dialog;
        }
    }


}
